package com.hystrix.command;

import com.hystrix.entity.User;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixRequestCache;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.ConcurrentHashMap;

/**
 * Hystrix 功能演示
 * - 自定义命令
 * - 请求缓存
 * */
public class UserCommand extends HystrixCommand<User>{

    private static final Logger logger = LoggerFactory.getLogger(UserCommand.class);

    private RestTemplate restTemplate;

    private static final ConcurrentHashMap<String,Object> cacheKey = new ConcurrentHashMap<>();

    private static final HystrixCommandKey GETTER_KEY = HystrixCommandKey.Factory.asKey("CommandKey");

    private String userName;

    private int id;

    /**
     * Construct a {@link HystrixCommand} with defined {@link Setter} that allows injecting property and strategy overrides and other optional arguments.
     * <p>
     * <p>
     * Do not create multiple {@link HystrixCommand} implementations with the same {@link com.netflix.hystrix.HystrixCommandKey} but different injected default properties as the first instantiated will win.
     * <p>
     * Properties passed in via {@link Setter#andCommandPropertiesDefaults} or {@link Setter#andThreadPoolPropertiesDefaults} are cached for the given {@link com.netflix.hystrix.HystrixCommandKey} for the life of the JVM
     * or until {@link com.netflix.hystrix.Hystrix#reset()} is called. Dynamic properties allow runtime changes. Read more on the <a href="https://github.com/Netflix/Hystrix/wiki/Configuration">Hystrix Wiki</a>.
     *
     * @param setter Fluent interface for constructor arguments
     */
    public UserCommand(Setter setter, RestTemplate restTemplate,int id) {
        super(setter);
        this.restTemplate = restTemplate;
        this.id = id;
    }

    /**
     * Implement this method with code to be executed when {@link #execute()} or {@link #queue()} are invoked.
     *
     * @return R response type
     * @throws Exception if command execution fails
     */
    @Override
    protected User run() throws Exception {

        logger.info("当前线程"+Thread.currentThread().getName());

        User responseUser = restTemplate.getForObject("http://provider-server/getUser/"+id,User.class);

        //清空缓存，返回数据为空
        //flushCache());
        return responseUser;
    }

    @Override
    protected User getFallback() {
        return new User();
    }

    /**
     * 开启缓存
     * */
    @Override
    protected String getCacheKey() {
        return String.valueOf(id);
    }

    /**
     * 清理无用缓存
     * */
    private void flushCache(){
        HystrixRequestCache.getInstance(GETTER_KEY, HystrixConcurrencyStrategyDefault.getInstance()).clear(String.valueOf(id));
    }

    //注解方式，请求缓存
//    @CacheResult(cacheKeyMethod = "getUserByCacheKey")
//    @com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand
//    public User getUserById(@CacheKey("id")int id){
//        return restTemplate.getForObject("http://provider-server/getUser/"+id,User.class);
//    }
//
//    public int getUserByCacheKey(int id){
//        return id;
//    }
//
//    @CacheRemove(commandKey = "getUserById")
//    @com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand
//    public void clearCache(@CacheKey("id")User user){
//
//    }
}
